<?php
/**
 * Author:xsc
 * Time:2023/10/13 9:57
 */

namespace App\Http\Middleware;

use App\Common\Constant;
use Closure;
use Illuminate\Http\Request;
use App\Exceptions\BusinessException;
use App\Common\ResponseCode;
use App\Repository\OpenPlatformRepo;
use App\Service\Common\CheckSignService;
use Illuminate\Support\Facades\Log;
use App\Service\Common\MerchantsService;

class CheckSignMiddleware
{

    public function handle(Request $request, Closure $next)
    {
        $data = $request->input();

        //Log::info("[中间件]新验签中间件:接收参数" . json_encode($data, 256));

        if (!$data) {
            throw new BusinessException(ResponseCode::PARAM_ILLEGAL, ['error' => '请求参数不能为空']);
        }

        // 平台信息
        $platform_no = $data['access_mid'];
        $platform_info = OpenPlatformRepo::getInstance()->getInfoByPlatformNo($platform_no);

        if (!$platform_info) {
            throw new BusinessException(ResponseCode::PARAM_ILLEGAL, ['error' => '平台不存在']);
        }

        if (!$platform_info['public_key']) {
            throw new BusinessException(ResponseCode::PARAM_ILLEGAL, ['error' => '平台未配置必要信息']);
        }

        try {
            // 1.验证签名
            CheckSignService::getInstance()->verifySign($data['data'], $data['sign'], $platform_info['public_key']);

            // 2.用自身私钥解密encryptKey得到aes_key
            $self_private_key = file_get_contents(config('selfpem.self_private'));

            $aes_key = CheckSignService::getInstance()->decryptByPri($data['encryptKey'], $self_private_key);

            // 3.用aes_key解密data得到请求体
            $body_str = CheckSignService::getInstance()->aesDecrypt($data['data'], $aes_key);

            Log::info("[中间件]新验签中间件:请求体" . $body_str);

            $body_arr = json_decode($body_str, true);

            // 对一些接口的限制,普通平台必传商户号,系统级平台可以操作所有
            $route_name = trim($request->getPathInfo(), '/');
            $mid = isset($body_arr['mid']) ? $body_arr['mid'] : '';
            $this->checkMid($platform_info, $route_name, $mid);

            // 反向写入请求
            foreach ($body_arr as $key => $value) {
                // 去掉请求体内的商户号，防止绕过签名操作其它商户内的藏品
                if ($key == 'access_mid') {
                    continue;
                }

                $request->offsetSet($key, $value);
            }

            return $next($request);
        } catch (\Exception $e) {
            Log::info("[中间件]新验签中间件:处理信息异常" . $e->getMessage());
            throw new BusinessException(ResponseCode::PARAM_ILLEGAL, ['error' => $e->getMessage()]);
        }
    }

    /**
     * 不同级别的平台,在操作$route_arr中的接口时,mid是否必传的限制
     * @param array $platform_info
     * @param string $route_name
     * @param string $mid
     * @return void
     * @throws BusinessException
     * @throws \RedisException
     * Author:xsc
     * Time:2023/10/16 15:00
     */
    public function checkMid(array $platform_info, string $route_name, string $mid = '')
    {

        /**
         * 此处拟定公用服务不用传递接入商户号的公用服务路由数组
         * 以下简称（公用服务）
         */
        $commonService = Constant::COMMON_SERVICE_ROUTE;

        /**
         * 公用服务直接略过
         */
        if (in_array($route_name, $commonService))
        {
            return;
        }

        /**
         * $platform_info['type'] 1：普通类型 2系统类型
         * 系统类型接入商户 直接略过
         */
        if ($platform_info['type'] == 2)
        {
            return;
        }

        // mid必传
        if (empty($mid))
            throw new BusinessException(ResponseCode::PARAM_ILLEGAL, ['error' => '商户号不能为空']);

        // 接入商户信息
        $merchants_info = MerchantsService::getInstance()->getInfoWithCache($mid);
        if (!$merchants_info)
            throw new BusinessException(ResponseCode::MERCHANTS_NOT_FUND);


        // 只能操作自己平台下的商户
        if ($merchants_info['platform_id'] != $platform_info['id'])
            throw new BusinessException(ResponseCode::PARAM_ILLEGAL, ['error' => '平台模式商户号异常']);
    }

}
